package com.run.go.gearbox.core.gearbox.disruptor;

import com.lmax.disruptor.BlockingWaitStrategy;
import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import com.run.go.gearbox.core.config.RunGoGearboxConf;
import com.run.go.gearbox.core.gearbox.AbstractGearbox;
import com.run.go.gearbox.core.gearbox.gear.Gear;
import com.run.go.gearbox.core.thread.NamedThreadFactory;
import com.run.go.gearbox.core.transmission.ExecuteEntity;

import java.util.Timer;
import java.util.TimerTask;

/**
 * CVT 变速箱  想做一个CVT 变速箱加速平缓还稳定，但是每次有要检查一下是否需要加速 是不是有点太烦人，
 * 要不要搞一个换挡策略， 那就是要把换挡单独抽象出来 换挡策略加变速箱组成一个完美的变速箱
 */
public class CVTGearbox extends AbstractGearbox {

    private Disruptor<ExecuteEntity> disruptor;

    private RingBuffer<ExecuteEntity> ringBuffer;

    /* 上次挂挡时间 */
    private volatile long gearTime = 0L;

    /* 延时降档 */
    private Timer downGearTimer = new Timer();

    public CVTGearbox(RunGoGearboxConf conf){
        super();
        this.gearNum = conf.getGearNum();
        this.power = conf.getPower();
        this.powerChain = conf.getPowerChain();
        this.gears = new Gear[1];
        this.gears[0] = newGear();
        U.compareAndSwapObject(this, CURRENT_GEAR_NUM, 0, 1);
        this.disruptor = new Disruptor<>(new ExecuteFactory() ,power, new NamedThreadFactory("disruptor-gear"),ProducerType.MULTI, new BlockingWaitStrategy());
        this.disruptor.handleEventsWith(new GearBoxWorkHandler());
        this.disruptor.setDefaultExceptionHandler(new DisruptorException());
    }

    @Override
    public void start() {
        super.start();
        this.ringBuffer = this.disruptor.start();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                downGear();
            }
        };
        downGearTimer.schedule(timerTask,5000,5000);
    }

    @Override
    public void stop() {
        super.stop();
        this.disruptor.shutdown();
        this.downGearTimer.cancel();
    }

    @Override
    public void execute(ExecuteEntity executeEntity) {

        /* 如果当前档位没有剩余马力 && 动力链条里面有堆积任务 就升档 */
        if(surplusPower() < 1 && ringBuffer.remainingCapacity() < powerChain) {

            long currentTime = System.currentTimeMillis();

            /* 给1秒钟加速时间 */
            if(this.gearTime == 0 || (currentTime - this.gearTime) > 1000){
                this.gearTime = System.currentTimeMillis();
                gear();
            }

        }

        /* 发送事件 */
        ringBuffer.publishEvent((executeEntity1,seq) ->{
            executeEntity1.setExecuteId(String.valueOf(seq));
            executeEntity1.setData(executeEntity.getData());
            executeEntity1.setFuture(executeEntity.getFuture());
            executeEntity1.setSqlType(executeEntity.getSqlType());
            executeEntity1.setSql(executeEntity.getSql());
        });

    }

    @Override
    protected Gear newGear() {
        return new DisruptorGear(power);
    }

    @Override
    public void downGear() {
        super.downGear();
    }

    private class GearBoxWorkHandler implements EventHandler<ExecuteEntity> {
        @Override
        public void onEvent(ExecuteEntity executeEntity, long sequence, boolean b) throws Exception {
            int num = 0;
            if(CVTGearbox.this.currentGearNum > 1){
                num = (int) (sequence % currentGearNum);
            }
            CVTGearbox.this.gears[num].execute(executeEntity);
        }
    }

}
